﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XNADota.Terrain;
using Microsoft.Xna.Framework;
using XNADota.Input;
using Microsoft.Xna.Framework.Input;

namespace XNADota.Camera
{
    class OverLookCamera : BaseCamera
    {
        private float _MoveSpeed = 5000.0f;
        private float _ZoomSpeed = 200.0f;
        private float _RotateSpeed = 1.0f;

        private float _InitX;
        private float _InitY;
        private float _InitZ;

        // boundary
        private float _MinX;
        private float _MinZ;
        private float _MaxX;
        private float _MaxZ;

        private static readonly Vector3 _IniRoation = new Vector3(0, 0, (float)Math.PI / 6);
        private static readonly Vector3 _IniForward = new Vector3(1, 0, 0);
        private static readonly Vector3 _IniRight = new Vector3(0, 0, 1);

        private Vector3 _Forward = new Vector3(1, 0, 0);
        private Vector3 _Right = new Vector3(0, 0, 1);

        private Vector3 _Rotation;
        private float _PositionToLookAt = 3000;

        public OverLookCamera(Game game, Landscape landscape)
            : base(game)
        {
            _InitX = landscape.LangscapeConfig.GridSize * (landscape.WarCraftEnvironment.Width - 1) / 2.0f;
            _InitY = _PositionToLookAt;
            _InitZ = landscape.LangscapeConfig.GridSize * (landscape.WarCraftEnvironment.Height - 1) / 2.0f;

            Position = new Vector3(_InitX, _InitY, _InitZ);
            LookAt = new Vector3(_InitX, 0, _InitZ);
            _Rotation = _IniRoation;

            CalculatePosition();
        }

        private void Reset()
        {
            Position = new Vector3(_InitX, _InitY, _InitZ);
            LookAt = new Vector3(_InitX, 0, _InitZ);
            _Rotation = _IniRoation;
        }

        public void SetBoundary(float minX, float minZ, float maxX, float maxZ)
        {
            _MinX = minX;
            _MaxX = maxX;

            _MinZ = minZ;
            _MaxZ = maxZ;
        }

        #region controller
        private Vector3 GetOffset(Vector3 position)
        {
            Vector3 offset = Vector3.Zero;
            if (position.X < _MinX) offset.X = _MinX - position.X;
            if (position.Z < _MinZ) offset.Z = _MinZ - position.Z;

            if (_MaxX < position.X) offset.X = _MaxX - position.X;
            if (_MaxZ < position.Z) offset.Z = _MaxZ - position.Z;

            return offset;
        }

        private void InBoundary()
        {
            //Vector3 offset = GetOffset(this.Position);
            //Translate(offset);
            Vector3 offset = GetOffset(this.LookAt);
            Translate(offset);
        }

        public void Translate(Vector3 offset)
        {
            this.Position += offset;
            this.LookAt += offset;
        }

        public void CalculatePosition()
        {
            Matrix Rotation = Matrix.CreateFromYawPitchRoll(_Rotation.X, _Rotation.Y, _Rotation.Z);
            Position = Vector3.Transform(new Vector3(0, _PositionToLookAt, 0), Rotation) + this.LookAt;
            this.Up = Vector3.Transform(new Vector3(1, 0, 0), Rotation);
        }

        public override void ProcessInput(GameTime gameTime, InputState inputState)
        {
            Vector3 offset = new Vector3(0, 0, 0);
            float seconds = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // Rotation
            if (inputState.IsKeyDown(Keys.Left))
            {
                _Rotation.X -= seconds * _RotateSpeed;
            }
            if (inputState.IsKeyDown(Keys.Right))
            {
                _Rotation.X += seconds * _RotateSpeed;
            }
            if (inputState.IsKeyDown(Keys.Up))
            {
                _Rotation.Z -= seconds * _RotateSpeed;
            }
            if (inputState.IsKeyDown(Keys.Down))
            {
                _Rotation.Z += seconds * _RotateSpeed;
            }

            Matrix Rotation = Matrix.CreateFromYawPitchRoll(_Rotation.X, _Rotation.Y, _Rotation.Z);

            // Translation
            _Forward = Vector3.Transform(_IniForward, Rotation);
            _Right = Vector3.Transform(_IniRight, Rotation);
            _Forward.Y = _Right.Y = 0;

            if (inputState.IsOnLeftMargin)
            {
                offset -= _Right * seconds * _MoveSpeed;
            }
            if (inputState.IsOnRightMargin)
            {
                offset += _Right * seconds * _MoveSpeed;
            }
            if (inputState.IsOnTopMargin)
            {
                offset += _Forward * seconds * _MoveSpeed;
            }
            if (inputState.IsOnBottomMargin)
            {
                offset -= _Forward * seconds * _MoveSpeed;
            }

            // Reset
            if (inputState.IsKeyDown(Keys.End))
                _Rotation = _IniRoation;

            // Reset All
            if (inputState.IsKeyDown(Keys.PageDown))
            {
                Reset();
            }

            _PositionToLookAt -= inputState.MouseDelta * seconds * _ZoomSpeed;

            this.Translate(offset);
            this.CalculatePosition();
            this.InBoundary();
        }
        #endregion
    }
}
